package cn.itsource.basic.util.baidu;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;

import static cn.hutool.http.HttpUtil.createGet;

public class DistanceUtil {
    /**
     * 工具类中，使用到的百度地图api的ak值（这个AK必须使用  服务端的ak）
     */
    private static final String ak = "sxDwKLAaz40VBrGkHMmXNKepySIEDHoV";
    /**
     * 地址转经纬坐标点
     */
    private static final String API_ADDRESS_TO_POINT = "http://api.map.baidu.com/geocoding/v3/?address=ADDRESS&output=json&ak=MYAK";
    /**
     * 计算2个point之间的驾车距离
     */
    private static final String API_CAL_DISTANCE_TWO_POINT = "http://api.map.baidu.com/routematrix/v2/driving?output=json&origins=POINT1&destinations=POINT2&ak=" + ak;


    /**
     * 根据传入的2个地址，计算2个地址之间的距离
     *
     * @param address1
     * @param address
     * @return 返回的计算单位是：米
     */
    public static Double calTwoAddressOfDistance(String address1, String address) {
        Point point1 = calAddressToPoint(address1);
        Point point2 = calAddressToPoint(address);
        if (point1 == null || point2 == null) {
            return null;
        }
        return calJuliByTwoPoint(point1, point2);
    }

    /**
     * 根据地址计算对应的经纬坐标
     *
     * @param address
     */
    private static Point calAddressToPoint(String address) {
        //下面的地址，是添加了必填参数之后的api地址
        String newApi = API_ADDRESS_TO_POINT.replace("ADDRESS", address).replace("MYAK", ak);
        //在后台，模拟发送一个http协议请求
        HttpRequest get = createGet (newApi);
        String content = get.execute ().body ();
        JSONObject jsonObject = JSONObject.parseObject(content);//将查询的json字符串转为json对象
        if (StrUtil.equals(jsonObject.getString("status"), "0")) {//返回的状态不是0，说明地址解析有误
            JSONObject pointObject = jsonObject.getJSONObject("result").getJSONObject("location");
            return new Point(pointObject.getDouble("lng"), pointObject.getDouble("lat"));
        } else {
            return null;
        }

    }

    /**
     * 计算2个经纬坐标点之间的 驾车距离
     *
     * @param p1
     * @param p2
     */
    private static double calJuliByTwoPoint(Point p1, Point p2) {
        HttpRequest get = createGet (API_CAL_DISTANCE_TWO_POINT.replace("POINT1", p1.parsePoint()).replace("POINT2", p2.parsePoint()));
        String content = get.execute ().body ();
        JSONObject jsonObject = JSONObject.parseObject(content);
        double distance = jsonObject.getJSONArray("result").getJSONObject(0).getJSONObject("distance").getDouble("value");

        return distance;
    }
    private static double PI = 3.14159265;
    private static double EARTH_RADIUS = 6378137;
    private static double RAD = Math.PI / 180.0;
    /**
     * @Description: 获取四至信息(最大最小经纬度)
     * @param lat
     * @param lng
     * @date 2019年4月25日 下午5:50:54
     */
    public static double[] getFourBounds(String lng, String lat, String[] pointArr) throws Exception {
        if (pointArr.length>1) {
            return getPolygonAround(pointArr);
        }
        return getCircleAround(Double.parseDouble(lng), Double.parseDouble(lat), Double.parseDouble(pointArr[0]));

    }

    /**
     * @method_name: 获取多边形四至信息
     * @param:
     * @params:  * @param null
     * @describe:
     * @creat_user: maizi
     * @creat_date: 2022/2/25
     * @creat_time: 11:33
     */
    public static double[] getPolygonAround(String[] pointArr) {
        // 获取中心点
        double maxLat = 0.0;
        double maxLng = 0.0;
        double minLat = 1000.0;
        double minLng = 1000.0;
        for (String str : pointArr) {
            double lng = Double.parseDouble(str.split(",")[0]);
            double lat = Double.parseDouble(str.split(",")[1]);
            if (lat > maxLat) {
                maxLat = lat;
            }
            if (lng > maxLng) {
                maxLng = lng;
            }
            if (lat < minLat) {
                minLat = lat;
            }
            if (lng < minLng) {
                minLng = lng;
            }
        }
        return new double[] { minLat, minLng, maxLat, maxLng };
    }


    /**
     * @method_name: 根据提供的经度和纬度、以及半径，取得此半径内的最大最小经纬度
     * @param:
     * @params:  <param name="lat">纬度</param>
     *     / <param name="lon">经度</param>
     *     / <param name="raidus">半径(米)</param>
     * @describe:
     * @creat_user: maizi
     * @creat_date: 2022/2/25
     * @creat_time: 11:33
     */
    public static double[] getCircleAround(double lon, double lat, double raidusMile)
    {
        Double latitude = lat;
        Double longitude = lon;
        Double degree = (24901 * 1609) / 360.0;
        Double dpmLat = 1 / degree;
        Double radiusLat = dpmLat * raidusMile;
        Double minLat = latitude - radiusLat;
        Double maxLat = latitude + radiusLat;
        Double mpdLng = degree * Math.cos(latitude * (PI / 180));
        Double dpmLng = 1 / mpdLng;
        Double radiusLng = dpmLng * raidusMile;
        Double minLng = longitude - radiusLng;
        Double maxLng = longitude + radiusLng;
        return new double[] { minLat, minLng, maxLat, maxLng };
    }
    /// <summary>
    /// 根据提供的两个经纬度计算距离(米) 误差10米 多了10米
    /// </summary>
    /// <param name="lng1">经度1</param>
    /// <param name="lat1">纬度1</param>
    /// <param name="lng2">经度2</param>
    /// <param name="lat2">纬度2</param>
    /// <returns></returns>
    public static double getDistance(double lng1, double lat1, double lng2, double lat2)
    {
        double radLat1 = lat1 * RAD;
        double radLat2 = lat2 * RAD;
        double a = radLat1 - radLat2;
        double b = (lng1 - lng2) * RAD;
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }



    /**
     * @method_name:
     * @param:
     * @params:  * @param lng1 lat1
     * @describe: 判断一个点是否在圆形区域内
     * @creat_user: maizi
     * @creat_date: 2022/2/25
     * @creat_time: 11:34
     */
    public static boolean isInCircle(double lng1, double lat1, double lng2, double lat2, String radius) {
        double distance = getDistance(lat1, lng1, lat2, lng2);
        double r = Double.parseDouble(radius);
        if (distance > r) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 通过传递两个地方的地址,判断以自己为圆心, 别人地址是否存在于圆半径内
     * @param myAddress 自己地址
     * @param otherAddress 别人地址
     * @param radius 圆心半径 ,单位:米
     * @return
     */
    public static boolean isInCircle(String myAddress,String otherAddress,double radius){
        Point myPoint = calAddressToPoint (myAddress);
        Point otherPoint = calAddressToPoint (otherAddress);
        double distance = calJuliByTwoPoint (myPoint, otherPoint);
        if (distance > radius) {
            return false;
        } else {
            return true;
        }
    }

    public static void main(String[] args) {
//        Point point = calAddressToPoint("武汉市江夏区纸坊大街地铁站");
//        System.out.println("转换的地址对应的经纬坐标地址 ："+point);
        boolean inCircle = isInCircle ("武汉市江夏区长城科技园-知业楼停车场", "武汉市洪山区广告图文", 3000);
        System.out.println ("inCircle = " + inCircle);


//        double juli = calJuliByTwoPoint(new Point(112.00, 22.00), new Point(88.12, 44.23));
//        System.out.println("距离是：" + juli);


//        //测试2个地址之间距离
//        double distance = calTwoAddressOfDistance("湖北省武汉市江夏区长城科技园", "湖北省武汉市洪山区光谷广场");
//        System.out.println(distance);
    }
}
